/*
 * Copyright (C) 2007  Vianney le Clément
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package fsahoraires.gui;

import java.util.ArrayList;
import java.util.List;

import fsahoraires.cours.*;
import fsahoraires.programmes.Programme;
import fsahoraires.programmes.Semestre;

public class UndoManager {

	private final Programme programme;
	private List<List<UndoItem>> history;
	private int currentIndex;

	private int transactionCount;
	private boolean undoing = false;

	public UndoManager(Programme programme) {
		this.programme = programme;
		clear();
	}

	public synchronized void clear() {
		history = new ArrayList<List<UndoItem>>();
		currentIndex = 0;
		transactionCount = 0;
	}
	
	private synchronized void add(UndoItem item) {
		if(undoing)
			return;
		List<UndoItem> list;
		if(transactionCount > 0) {
			list = history.get(currentIndex);
		} else {
			while(history.size() > currentIndex)
				history.remove(currentIndex);
			
		}
	}
	
	private final CoursManagerListener cmListener = new CoursManagerListener() {
		public void modified(Cours cours) {
			// TODO Auto-generated method stub
	
		}
	
		public void disposed(Cours cours) {
			// TODO Auto-generated method stub
	
		}
	
		public void beforeModify(Cours cours) {
			// TODO Auto-generated method stub
	
		}
	
		public void added(Cours cours) {
			// TODO Auto-generated method stub
	
		}
	};

	private interface UndoItem {
		void undo();

		void redo();
	}

	private class SemestreItem implements UndoItem {
		private Semestre semestre;
		private final boolean removed;

		/**
		 * @param semestre
		 * @param removed true pour opération de suppression, false pour
		 *            opération d'ajout
		 */
		public SemestreItem(Semestre semestre, boolean removed) {
			this.semestre = semestre;
			this.removed = removed;
		}

		public void redo() {
			if (removed) {
				semestre.dispose();
			} else {
				new Semestre(programme, semestre);
			}
		}

		public void undo() {
			if (removed) {
				semestre = new Semestre(programme, semestre);
			} else {
				semestre.dispose();
			}
		}
	}

	private class CoursItem implements UndoItem {
		private Semestre semestre;
		private Cours cours;
		private final boolean removed;

		public CoursItem(Cours cours, boolean removed) {
			this.cours = cours;
			this.removed = removed;
		}

		public void redo() {
			if (removed) {
				semestre = programme.get(semestre);
				semestre.remove(cours);
			} else {
				new Semestre(programme, semestre);
			}
		}

		public void undo() {
			if (removed) {
				new Semestre(programme, semestre);
			} else {
				semestre = programme.get(semestre);
				semestre.remove(cours);
			}
		}
	}

	private class CacheItem implements UndoItem {
		private Cours cours;
		private final boolean removed;

		public CacheItem(Cours cours, boolean removed) {
			this.cours = cours;
			this.removed = removed;
		}

		public void redo() {
			cours = programme.getManager().getCours(cours);
			if (removed) {
				cours.dispose();
			}
		}

		public void undo() {
			cours = programme.getManager().getCours(cours);
			if (!removed) {
				cours.dispose();
			}
		}
	}

	private class CoursModifiedItem implements UndoItem {
		private Cours cours;
		private String titreA, titreB;
		private String abreviationA, abreviationB;
		private float creditsA, creditsB;
		private float heuresA, heuresB;
		private Horaire horaire1A, horaire1B, horaire2A, horaire2B;

		public CoursModifiedItem(Cours cours) {
			this.cours = cours;
			titreA = cours.getTitre();
			titreB = titreA;
			abreviationA = cours.getAbreviation();
			abreviationB = abreviationA;
			creditsA = cours.getCredits();
			creditsB = creditsA;
			heuresA = cours.getHeures();
			heuresB = heuresA;
			horaire1A = cours.getHoraire(1);
			horaire1B = horaire1A;
			horaire2A = cours.getHoraire(2);
			horaire2B = horaire2A;
		}

		public void update(Cours c) {
			if (cours.equals(c)) {
				titreB = cours.getTitre();
				abreviationB = cours.getAbreviation();
				creditsB = cours.getCredits();
				heuresB = cours.getHeures();
				horaire1B = cours.getHoraire(1);
				horaire2B = cours.getHoraire(2);
			}
		}

		public void redo() {
			cours = programme.getManager().getCours(cours);
			cours.setTitre(titreB);
			cours.setAbreviation(abreviationB);
			cours.setCredits(creditsB);
			cours.setHeures(heuresB);
			cours.setHoraire(1, horaire1B);
			cours.setHoraire(2, horaire2B);
		}

		public void undo() {
			cours = programme.getManager().getCours(cours);
			cours.setTitre(titreB);
			cours.setAbreviation(abreviationB);
			cours.setCredits(creditsB);
			cours.setHeures(heuresB);
			cours.setHoraire(1, horaire1B);
			cours.setHoraire(2, horaire2B);
		}
	}
}
